# encoding:utf-8
# autocomplete for zeppelin page
import urllib
import re
import sys
import importlib
import inspect
from types import FunctionType, BuiltinFunctionType, MethodType

AVAILABLE_PACKAGES = {"np": "numpy",
                      "pd": "pandas",
                      "tf": "tensorflow",
                      "tr": "torch",
                      "sk": "sklearn",
                      "pd.Series": "pandas.core.series",
                      "pd.DataFrame": "pandas.core.frame"}


def getParamsInfo(attr):
    try:
        return list(inspect.signature(attr).parameters.keys())
    except (ValueError, AttributeError) as e1:
        return []
    except Exception:
        return []


def getFuncInfo(obj):
    recommendFuncs = {}
    for attr in dir(obj):
        if not re.search("^__.*__$", attr) and not re.search("^_.*$", attr):
            # 排除私有方法
            res = getattr(obj, attr)
            if isinstance(res, BuiltinFunctionType):
                recommendFuncs[res.__name__] = {"args": getParamsInfo(res), "type": "built-in"}
            elif isinstance(res, MethodType):
                recommendFuncs[res.__name__] = {"args": getParamsInfo(res), "type": "bound-func"}
            elif isinstance(res, FunctionType):
                recommendFuncs[res.__name__] = {"args": getParamsInfo(res), "type": "class-func"}

    return recommendFuncs


def inferenceType(methods):
    candidate_methods = {}
    for method in methods:
        if method in AVAILABLE_PACKAGES.keys():
            # 如果是顶级包，导入
            package = importlib.import_module(AVAILABLE_PACKAGES.get(method))
            candidate_methods = getFuncInfo(package)
        else:
            if candidate_methods is not None:
                if method in candidate_methods.keys():
                    candidate_methods = {k: v for k, v in candidate_methods.items() if v.get("type") == "built-in"}
    return candidate_methods


def extractIdentifier(snippet):
    try:
        raw_name = snippet.strip().split("\n")[-1]
        return raw_name.split("=")[-1].split(".")[0].strip()
    except:
        return ""


def afterSplit(methods):
    if methods[0] == "pd":
        temp = methods[0] + "." + methods[1]
        if temp in AVAILABLE_PACKAGES.keys():
            methods.pop(0)
            methods.pop(0)
            methods.insert(0, temp)

    return methods


def findDefinition(identifier, snippet):
    parts = list(map(lambda line: line.strip(), snippet.strip().split("\n")))
    method_stack = []
    for part in parts[::-1]:
        if identifier is not None:
            # 从后往前，找定义语句
            if identifier in AVAILABLE_PACKAGES.keys():
                # 如果标志符已经是顶级包
                raw_definition = part.split("=")[-1].strip()[len(identifier):].strip()
                method_stack = list(
                    filter(lambda m: m != '', re.sub(r"\(.*?\)|\{.*?\}|\[.*?\]", "", raw_definition).split('.')))
                method_stack.insert(0, identifier)
                break
            else:
                head = re.search("^{name}\s*=\s*".format(name=identifier), part)
                if head is not None:
                    # 截取，不能用等号去切，因为参数中可能有等号等
                    raw_definition = part[len(head.group()):].strip()
                    # 去除括号内全部参数，
                    clear_definition = re.sub(r"\(.*?\)|\{.*?\}|\[.*?\]", "", raw_definition).split(".")
                    clear_definition = afterSplit(clear_definition)
                    clear_definition.extend(method_stack)
                    if clear_definition[0] not in AVAILABLE_PACKAGES.keys():
                        identifier = clear_definition.pop(0)
                    else:
                        identifier = None
                    method_stack = clear_definition
        else:
            break

    return method_stack


def extractFuncInfo(snippet):
    identifier = extractIdentifier(snippet)
    if None is not identifier and identifier != "":
        definition_list = findDefinition(identifier, snippet)
        return inferenceType(definition_list)
    else:
        return {}


if __name__ == '__main__':
    print(extractFuncInfo(sys.argv[1]))